package org.durandj.ystream.server.ui;

import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.ByteBuffer;

import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.ListModel;

import org.durandj.ystream.server.ClientManager;
import org.durandj.ystream.server.ClientManagerListener;
import org.durandj.ystream.server.Server;
import org.durandj.ystream.server.message.Message;
import org.durandj.ystream.server.message.MessageID;
import org.durandj.ystream.server.message.Message.Priority;
import org.durandj.ystream.server.util.ByteBufferUtils;

// TODO: Remove Jigloo code.
/**
 * A graphical UI for normal people. This is a rather simple way of managing the server with easier to
 * understand controls. All messages and notifications are reported to the GUI elements instead of
 * the console.
 * 
 * @author durandj
 * @version 1.0
 *
 */
public class ServerGUI extends javax.swing.JFrame implements ServerUI
{
	// TODO: I need to add something for showing the current playlist,
	// TODO: the people connected to the server, a button for dropping,
	// TODO: banning, rearranging the playlist, enabling/disabling the server,
	// TODO: a listing of total number of connections, currently playing selection,
	// TODO: duration of current song, number of files transfered at a time,
	// TODO: a toggle for allowing client submittions.
	
	// TODO: Get rid of the Jigloo code!
	
	// TODO: Wishlist: Current action on a by connection basis.
	// TODO:		   File upload size limit.
	// TODO:		   Maximum number of connections limit.
	// TODO:		   Information about individual files being displayed.
	
	{
		//Set Look & Feel
		try
		{
			javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	private static final long serialVersionUID = -1721929092148703785L;
	
	private JMenu menuOptions;
	private JPanel panelPlaylist;
	private JPanel panelClients;
	private JPanel panelPlaylistControls;
	private JButton btnAdd;
	private JButton btnDown;
	private JButton btnUp;
	private JButton btnRemove;
	private JList listPlaylist;
	private JScrollPane scrollPlaylist;
	private JButton btnBan;
	private JButton btnDisconnect;
	private JTextField txtClientCount;
	private JMenuItem menuExit;
	private JLabel lblClientCount;
	private JPanel panelClientControls;
	private JList listClients;
	private JScrollPane scrollClientsList;
	private JMenuItem menuPreferences;
	private JSeparator menuOptionsSeparator2;
	private JMenuItem menuAbout;
	private JSeparator menuOptionsSeparator1;
	private JMenuBar menubar;
	private ListModel playlistModel;
	
	/**
	 * The reference to the client manager that the UI uses to listen for
	 * changes in the number of clients.
	 */
	private ClientManager clientManager;

	/**
	 * Creates a server GUI.
	 */
	public ServerGUI()
	{
		super();
		initGUI();
		
		setVisible(true);
	}
	
	/**
	 * Initializes the components of the server GUI.
	 */
	private void initGUI()
	{
		try
		{
			BoxLayout thisLayout = new BoxLayout(getContentPane(), javax.swing.BoxLayout.X_AXIS);
			getContentPane().setLayout(thisLayout);
			this.setTitle("YStream Server");
			{
				menubar = new JMenuBar();
				setJMenuBar(menubar);
				{
					menuOptions = new JMenu();
					menubar.add(menuOptions);
					menuOptions.setText("Options");
					{
						menuPreferences = new JMenuItem();
						menuOptions.add(menuPreferences);
						menuPreferences.setText("Preferences");
						
						menuPreferences.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent e)
							{
								// TODO Auto-generated method stub
							}
						});
					}
					{
						menuOptionsSeparator1 = new JSeparator();
						menuOptions.add(menuOptionsSeparator1);
					}
					{
						menuAbout = new JMenuItem();
						menuOptions.add(menuAbout);
						menuAbout.setText("About");
						
						menuAbout.setToolTipText("About YStream Server.");
						
						menuAbout.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								new AboutDialog(ServerGUI.this).setVisible(true);
							}
						});
					}
					{
						menuOptionsSeparator2 = new JSeparator();
						menuOptions.add(menuOptionsSeparator2);
					}
					{
						menuExit = new JMenuItem();
						menuOptions.add(menuExit);
						menuExit.setText("Exit");
						
						menuExit.setToolTipText("Exits the server.");
						
						menuExit.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								Server.getServer().queueMessage(new Message(Priority.HIGH, MessageID.KILL, this));
							}
						});
					}
				}
			}
			{
				panelPlaylist = new JPanel();
				getContentPane().add(panelPlaylist);
				panelPlaylist.setLayout(null);
				{
					scrollPlaylist = new JScrollPane();
					panelPlaylist.add(scrollPlaylist);
					scrollPlaylist.setBounds(0, 0, 282, 247);
					{
						playlistModel = new DefaultComboBoxModel();
						
						listPlaylist = new JList();
						scrollPlaylist.setViewportView(listPlaylist);
						listPlaylist.setModel(playlistModel);
						listPlaylist.setPreferredSize(new java.awt.Dimension(276, 189));
						
						listPlaylist.setToolTipText("The current playlist.");
					}
				}
				{
					panelPlaylistControls = new JPanel();
					panelPlaylist.add(panelPlaylistControls);
					panelPlaylistControls.setBounds(0, 247, 282, 121);
					panelPlaylistControls.setLayout(null);
					{
						btnAdd = new JButton();
						panelPlaylistControls.add(btnAdd);
						btnAdd.setText("Add");
						btnAdd.setBounds(0, 0, 282, 28);
						
						btnAdd.setToolTipText("Adds a new song to the playlist.");
						
						btnAdd.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								// TODO Auto-generated method stub
								
							}
						});
					}
					{
						btnRemove = new JButton();
						panelPlaylistControls.add(btnRemove);
						btnRemove.setText("Remove");
						btnRemove.setBounds(0, 31, 282, 28);
						
						btnRemove.setToolTipText("Removes the currently selected song from the playlist.");
						
						btnRemove.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								// TODO Auto-generated method stub
								
							}
						});
					}
					{
						btnUp = new JButton();
						panelPlaylistControls.add(btnUp);
						btnUp.setText("Move Up");
						btnUp.setBounds(0, 62, 282, 28);
						
						btnUp.setToolTipText("Moves the currently selected song up in the playlist.");
						
						btnUp.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								// TODO Auto-generated method stub
								
							}
						});
					}
					{
						btnDown = new JButton();
						panelPlaylistControls.add(btnDown);
						btnDown.setText("Move Down");
						btnDown.setBounds(0, 93, 282, 28);
						
						btnDown.setToolTipText("Moves the currently selected song down in the playlist.");
						
						btnDown.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								// TODO Auto-generated method stub
								
							}
						});
					}
				}
			}
			{
				panelClients = new JPanel();
				getContentPane().add(panelClients);
				panelClients.setLayout(null);
				{
					scrollClientsList = new JScrollPane();
					panelClients.add(scrollClientsList);
					scrollClientsList.setBounds(0, 0, 282, 278);
					{
						listClients = new JList();
						scrollClientsList.setViewportView(listClients);
						
						listClients.setToolTipText("The currently connected clients.");
					}
				}
				{
					panelClientControls = new JPanel();
					panelClients.add(panelClientControls);
					panelClientControls.setBounds(0, 275, 282, 96);
					panelClientControls.setLayout(null);
					{
						lblClientCount = new JLabel();
						panelClientControls.add(lblClientCount);
						lblClientCount.setText("Clients Connected:");
						lblClientCount.setBounds(3, 8, 105, 16);
					}
					{
						txtClientCount = new JTextField();
						panelClientControls.add(txtClientCount);
						txtClientCount.setBounds(111, 3, 75, 28);
						txtClientCount.setEditable(false);
						
						txtClientCount.setToolTipText("The number of currently connected clients.");
					}
					{
						btnDisconnect = new JButton();
						panelClientControls.add(btnDisconnect);
						btnDisconnect.setText("Disconnect");
						btnDisconnect.setBounds(0, 34, 282, 28);
						
						btnDisconnect.setToolTipText("Disconnects the currently selected client.");
						
						btnDisconnect.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								// Lets get the list of currently selected items from the client list.
								// We then need to check to see if the list is empty and if so let the user
								// know that they aren't using this command right.
								Object objects[] = listClients.getSelectedValues();
								if(objects.length == 0)
								{
									JOptionPane.showMessageDialog(null,
									                              "You must select a client from the client list.",
									                              "Must select a client",
									                              JOptionPane.ERROR_MESSAGE);
									return;
								}
								
								for(Object obj : objects)
								{
									ByteBuffer buf = ByteBufferUtils.stringToByteBuffer(obj.toString());
									Server.getServer().getNetworkDaemon().queueMessage(new Message(Priority.LOW, MessageID.DISCONNECT_CLIENT, this, buf));
									//clientManager.queueMessage(new Message(Priority.LOW, MessageID.DISCONNECT_CLIENT, this, buf));
								}
							}
						});
					}
					{
						btnBan = new JButton();
						panelClientControls.add(btnBan);
						btnBan.setText("Ban");
						btnBan.setBounds(0, 65, 282, 28);
						
						btnBan.setToolTipText("Bans the currently selected client.");
						
						btnBan.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent arg0)
							{
								// Lets get the list of currently selected items from the client list.
								// We then need to check to see if the list is empty and if so let the user
								// know that they aren't using this command right.
								int indices[] = listClients.getSelectedIndices();
								if(indices.length == 0)
								{
									JOptionPane.showMessageDialog(null,
									                              "You must select a client from the client list.",
									                              "Must select a client",
									                              JOptionPane.ERROR_MESSAGE);
									return;
								}
								
								// TODO Auto-generated method stub
								
							}
						});
					}
				}
			}
			pack();
			this.setSize(581, 433);
			this.setIconImage(new ImageIcon("./lib/YStream.png").getImage());
			
			// We need to know about some other window events so lets listen in on those.
			addWindowListener(new WindowAdapter() {
				@Override
				public void windowClosing(WindowEvent e)
				{
					Server.getServer().queueMessage(new Message(Priority.HIGH, MessageID.KILL, this));
				}
			});
		}
		catch (Exception e)
		{
		    //add your error handling code here
			e.printStackTrace();
		}
	}
	
	@Override
	public void paint(Graphics g)
	{
		// We'll handle all our custom painting first.
		int width;
		int height;
		
		width = panelPlaylist.getWidth();
		height = panelPlaylist.getHeight();
		
		scrollPlaylist.setBounds(scrollPlaylist.getX(),
		                         scrollPlaylist.getY(),
		                         width,
		                         height - panelPlaylistControls.getHeight() - 6);
		
		panelPlaylistControls.setBounds(panelPlaylistControls.getX(),
		                                scrollPlaylist.getHeight(),
		                                width,
		                                panelPlaylistControls.getHeight());
		
		btnAdd.setBounds(btnAdd.getX(),
		                 btnAdd.getY(),
		                 width,
		                 btnAdd.getHeight());
		
		btnRemove.setBounds(btnRemove.getX(),
		                    btnRemove.getY(),
		                    width,
		                    btnRemove.getHeight());
		
		btnUp.setBounds(btnUp.getX(),
		                btnUp.getY(),
		                width,
		                btnUp.getHeight());
		
		btnDown.setBounds(btnDown.getX(),
		                  btnDown.getY(),
		                  width,
		                  btnDown.getHeight());
		
		width = panelClients.getWidth();
		height = panelClients.getHeight();
		
		scrollClientsList.setBounds(scrollClientsList.getX(),
		                            scrollClientsList.getY(),
		                            width,
		                            height - panelClientControls.getHeight() - 6);
		
		panelClientControls.setBounds(panelClientControls.getX(),
		                              scrollClientsList.getHeight(),
		                              width,
		                              panelClientControls.getHeight());
		
		btnDisconnect.setBounds(btnDisconnect.getX(),
		                        btnDisconnect.getY(),
		                       	width,
		                       	btnDisconnect.getHeight());
		
		btnBan.setBounds(btnBan.getX(),
		                 btnBan.getY(),
		                 width,
		                 btnBan.getHeight());
		
		// TODO: Handle custom drawing code.
		
		// Now that we have all of our own drawing done lets
		// let the JFrame class take care of the rest.
		super.paint(g);
	}
	
	@Override
	public void destroy()
	{
		// TODO:
		
		// Allow the super class to do the rest of the cleanup.
		super.dispose();
	}
	
	/* (non-Javadoc)
	 * @see org.durandj.ystream.server.ui.ServerUI#setClientManager(org.durandj.ystream.server.ClientManager)
	 */
	@Override
	public void setClientManager(ClientManager manager)
	{
		if(manager == null)
			throw new NullPointerException("Must give a valid client manager reference.");
		
		clientManager = manager;
		clientManager.addListener(new ClientManagerListener() {
			@Override
			public void clientsChanged()
			{
				txtClientCount.setText(Integer.toString(clientManager.getClients().size()));
				
				listClients.setListData(clientManager.getClients().toArray());
			}
		});
	}
}
